﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using RuoVea.ExFilter.Language;
using System.Security.Claims;

namespace RuoVea.ExFilter;

/// <summary>
/// 进行全局的异常日志收集 "ExceptionLog": {"Enabled":true,"LogMore":false,"LogToFile":true}
/// </summary>
public class ExceptionFilter : ExceptionFilterAttribute
{
    private readonly IRestfulFilterLog _restfulFilterLog;
    private readonly IRESTfulResult _restfulResult;
    private readonly ExceptionLog _options;
/// <summary>
/// 
/// </summary>
/// <param name="restfulFilterLog"></param>
/// <param name="restfulResult"></param>
/// <param name="options"></param>
    public ExceptionFilter(IRestfulFilterLog restfulFilterLog, IRESTfulResult restfulResult ,IOptions<ExceptionLog> options)
    {
        _restfulFilterLog = restfulFilterLog;
        _restfulResult = restfulResult;
        _options = options.Value;
    }
    /// <summary>
    /// 注入 全局异常处理 [进行全局的异常日志收集]
    /// </summary>
    /// <param name="context"></param>
    public override void OnException(ExceptionContext context)
    {
        if (context.IsNonException()) return;
        if (context.ExceptionHandled) return; 

        if (!_options.Enabled) return;

        try
        {
            LogMessage logMessage = new LogMessage() { OperationTime = DateTime.Now };

            logMessage.ExceptionInfo = context.Exception.InnerException == null ? context.Exception?.Message : context.Exception?.InnerException?.Message;
            logMessage.Url = context.HttpContext.Request.GetRequestUrlAddress();
            logMessage.Ip=context.HttpContext.GetIp();
            logMessage.Host = context.HttpContext.Request.GetRequestHost();
            logMessage.Browser=context.HttpContext.GetBrowser();
            logMessage.Class = context.ActionDescriptor?.DisplayName;
            logMessage.ExceptionInfo = logMessage.ExceptionInfo;
            logMessage.ExceptionSource = context.Exception?.Source;
            logMessage.ExceptionRemark = context.Exception?.StackTrace;

            //拦截处理
            if (!context.ExceptionHandled)
            {
                // 判断是否是友好异常
                if (context.Exception is ParamiterException paramiter)
                    context.Result = new JsonResult(_restfulResult.RESTfulResult(CodeStatus.InternalServerError,message: paramiter.Message));
                else if (context.Exception is ConnctionException connEx)
                    context.Result = new JsonResult(_restfulResult.RESTfulResult(CodeStatus.RequestTimeout, message: connEx.Message));

                else if (context.Exception is ArgumentOutOfRangeException argumentOutOfRangeEx)
                    context.Result = new JsonResult(_restfulResult.RESTfulResult(CodeStatus.BadRequest, message: argumentOutOfRangeEx.Message));
                else if (context.Exception is ArgumentNullException argumentNullEx)
                    context.Result = new JsonResult(_restfulResult.RESTfulResult(CodeStatus.BadRequest, message: argumentNullEx.Message));
                else if (context.Exception is ArgumentException argumentEx)
                    context.Result = new JsonResult(_restfulResult.RESTfulResult(CodeStatus.BadRequest, message: argumentEx.Message));

                else
                    context.Result = new JsonResult(_restfulResult.RESTfulResult(CodeStatus.InternalServerError, message: $"{CodeStatus.InternalServerError.GetDescription()}:{context.Exception?.Message}"));

                if (_options.LogToFile)
                    LogFactory.Error(logMessage);
            }
            if (_options.LogMore)
            {
                var userContext = context.HttpContext.User;
                ExceptionVo exceptionVo = new ExceptionVo
                {
                    Account =   userContext?.FindFirstValue(ClaimConst.CLAINM_ACCOUNT),
                    Name =  userContext?.FindFirstValue(ClaimConst.CLAINM_NAME),
                    ClassName = context.Exception?.TargetSite?.DeclaringType?.FullName,
                    MethodName = context.Exception?.TargetSite?.Name,
                    ExceptionMessage = context.Exception?.Message,
                    ExceptionSource = context.Exception?.Source,
                    StackTrace = context.Exception?.StackTrace,
                    ParamsObj = context.Exception?.TargetSite?.GetParameters()?.ToString(),
                    ExceptionTime = logMessage.OperationTime,
                };
                _restfulFilterLog.ExceptionLog(exceptionVo);
            }
        }
        catch (Exception ex)
        {
            // 方法一：返回出去的是字符串类型
            context.Result = new JsonResult(_restfulResult.RESTfulResult(CodeStatus.InternalServerError, message: $"{CodeStatus.InternalServerError.GetDescription()}:{context.Exception?.Message}"));
            try
            {
                if (_options.LogMore)
                    LogFactory.Error(i18n.servererrorlogskip + ex.Message);
            }
            catch { }
        }
        finally
        {
            context.ExceptionHandled = true;
        }
    }
}